Demandez le programme !

L'algorithme des $k$ plus proches voisins est dans la section Algorithmique.

Introduction à l'algorithme des $k$ plus proches voisins

L’algorithme des $k$ plus proches voisins est l’un des algorithmes utilisés dans le domaine de l’intelligence artificielle.
C'est un algorithme d'apprentissage automatique supervisé qui attribue une catégorie à un élément en fonction de la classe majoritaire des ses plus proches voisins dans l'échantillon d'entraînement.

Son principe peut être résumé par cette phrase : Dis-moi qui sont tes amis et je te dirai qui tu es.

Cet algorithme d'apprentissage automatique est par exemple utilisé par des entreprises d'Internet comme Amazon, Netflix, Spotify ou iTunes afin de prévoir si vous seriez ou non intéressés par un produit donné en utilisant vos données et en les comparant à celles des clients ayant acheté ce produit particulier.

Cet algorithme a été introduit en 1951 par Fix et Hodges dans un rapport de la faculté de médecine aéronautique de la US Air Force.

Exemple introductif

Dans cette introduction, nous considérons un jeu de données constitué de la façon suivante :

Imaginez la situation suivante dans un jeu :

Vous introduisez un nouveau personnage dont vous ne connaissez pas le type. Vous possédez les caractéristiques de ce nouveau personnage. Le but de l'algorithme KNN ($k$ Nearest Neighbors = $k$ plus proches voisins en français) est de déterminer le type de ce nouveau personnage.

Les données sont stockées dans un fichier csv téléchargeable : fichier csv à télécharger

Voici un aperçu des données :

Voici une représentation de ces données :

Nous introduisons une nouvelle donnée (appelée cible dans notre exemple) avec ses deux caractéristiques : une force de 12 et un courage de 12,5 . Le but de l'algorithme KNN des $k$ plus proches voisins est de déterminer le type de cette nouvelle donnée.

  1. Dans un premier, il faut fixer le nombre de voisins. Nous allons choisir $k$=7.

    Voici une nouvelle représentation avec la cible et la recherche des 7 voisins les plus proches proches, ceux qui se trouvent dans le cercle bleu :

    En utilisant les voisins de type "chevalier" et de type "fantassin", déterminer le type le plus probable de notre cible.

  2. On considère désormais la valeur $=13$. Voici une nouvelle représentation avec la cible et la recherche des 13 voisins les plus proches proches, ceux qui se trouvent dans le cercle bleu : Déterminer le type le plus probable de notre cible dans ce cas ?

Code de déblocage de la correction :

  1. La valeur $k$=7 est ici un choix arbitraire. Cette valeur doit néanmoins être choisie judicieusement : trop faible, la qualité de la prédiction diminue ; trop grande, la qualité de la prédiction diminue aussi. Il suffit d'imaginer qu'il existe une classe prédominante en nombre. Avec une grande valeur de $k$, cette classe remporterait la prédiction à chaque fois.

  2. Nous avons utilisé une distance schématisée par un disque. Ce choix est discutable. Il faut faire attention à la distance euclidienne qui n'a de sens que dans un repère orthonormé. Nous aurions pu choisir une autre distance.

  3. Il est facile de représenter graphiquement les données avec 1 à 3 caractéristiques. Nous ne pouvons pas représenter des données avec des caractéristiques supérieures à 3 mais l'algorithme reste opérationnel.

L'algorithme

Pour prédire la classe d’un nouvel élément, il faut des données :

Une fois ces données modélisées, nous pouvons formaliser l'algorithme de la façon suivante :

  1. Trouver, dans l’échantillon, les $k$ plus proches voisins de l'élément à déterminer.

  2. Parmi ces proches_voisins, trouver la classification majoritaire.

  3. Renvoyer la classification_majoritaire comme type cherché de l'élément.

Ce qui nous donne l'algorithme naïf suivant :

Influence de la distance choisie

Nous reprenons le même ensemble de données :

Nous introduisons une cible : force = 5 et courage = 12,5

  1. On choisit $k$=4 et la distance schématisée par un disque .

    1. Quel est le type de notre donnée cible ? Quel est le problème ?

    2. Donner une valeur de $k$ qui permette de décider du type de notre donnée cible ?

    3. Donner pour cette valeur de $k$ le type de la donnée cible.

  2. On choisit $k=9$. Pour la distance, on décide que les valeurs de la force n'ont pas d'importance. La distance dépend du courage.

    Quel est le type de notre donnée cible ?

  3. On choisit $k=5$. Pour la distance, on décide que les valeurs du courage n'ont pas d'importance. La distance dépend de la force.

    Quel est le type de notre donnée cible ?

Code de déblocage de la correction :

Comment représenter ce type de données en Python ?

Les figures précédentes ont été réalisées grâce au module matplotlib, librairie très utile en Python.

    1. Tester le script Python suivant :

      from math import *
      import matplotlib.pyplot as plt
      
      # Données de type 1
      liste_x_1 = [1, 3, 8, 13]
      liste_y_1 = [28, 27.2, 37.6, 40.7]
      
      # Données de type 2
      liste_x_2 = [2, 3, 10, 15]
      liste_y_2 = [30, 26, 39, 35.5]
      
      plt.axis([0, 15, 0, 50]) # Attention [x1, x2, y1, y2]
      plt.xlabel('Caractéristique 1')                     # premier commentaire attendu
      plt.ylabel('Caractéristique 2')
      plt.title('Représentation des deux types')
      plt.axis('equal') # Pour avoir un repère orthonormé
      plt.grid()
      plt.scatter(liste_x_1, liste_y_1, label='type 1')    # second commentaire attendu
      plt.scatter(liste_x_2, liste_y_2, label='type 2')
      plt.legend()
      plt.show()
      
    2. Remplacer les deux commentaires attendus par un commentaire expliquant le rôle des fonctions plt.label et plt.scatter.

    1. Vous pouvez ajouter des formes (rectangle, ellipse, etc.).

      Exécuter le script suivant :

      from math import *
      import matplotlib.pyplot as plt
      
      # Données de type 1
      liste_x_1 = [1, 3, 8, 13]
      liste_y_1 = [28, 27.2, 37.6, 40.7]
      
      # Données de type 2
      liste_x_2 = [2, 3, 10, 15]
      liste_y_2 = [30, 26, 39, 35.5]
      
      fig, ax = plt.subplots()
      
      plt.axis([0, 15, 0, 50]) # Attention [x1, x2, y1, y2]
      plt.xlabel('Caractéristique 1')
      plt.ylabel('Caractéristique 2')
      plt.title('Représentation des deux types')
      plt.axis('equal') # pour avoir un repère orthonormé. Faire des tests.
      plt.grid()
      plt.scatter(liste_x_1, liste_y_1, label='type 1')
      plt.scatter(liste_x_2, liste_y_2, label='type 2')
      plt.legend()
      
      # Ajout d'un cercle (ou d'une ellipse)
      ax.add_artist(plt.Circle((6, 30), 4, edgecolor='b', facecolor='none'))
      
      # Ajout d'un rectangle
      ax.add_artist(
          plt.Rectangle((6, 0), 2, 50,
                            edgecolor='black', facecolor='none',
                            fill=True, hatch='/', linestyle='dashed',
                            linewidth=3, zorder=1))
      
      plt.show()
      
    2. Quel est le rôle du premier argument (6, 30) de la fonction plt.Circle ?

    3. Quel est le rôle des trois premiers arguments (6, 0), 2 et 50 de la fonction plt.Rectangle ?

Code de déblocage de la correction :

Influence de la valeur de $k$ choisie

Sur un champ de bataille de la Première Guerre Mondiale un mémorial a été construit. Afin de réaliser une extension, des fouilles préventives ont été réalisées par l'INRAP (Institut National de Recherches Archéologiques Préventives).
Au cours de ces fouilles, différents objets ou éléments de squelettes humains ont été trouvés. L'étude de ces découvertes a permis d'identifier la nationalité de nombreux artefacts retrouvés : soit allemand, anglais ou français.
Le plan ci-dessous représente la zone de fouille et la position des éléments dont l'origine a été identifiée. L'unité est le mètre.

Un élément d'un squelette a été retrouvé en $(10;4)$ ; il est représenté par un losange couleur magenta sur le plan.
L'objectif est de déterminer une origine probable pour cet élément de squelette avant de le déposer dans un ossuaire.

plan des fouilles

La distance qui sera prise en compte est la distance dite de Tchebychev. (la définition précise de celle-ci sera donnée au 2.)
Ce que vous devez seulement savoir sur cette distance pour cet exercice c'est que l'ensemble des points se trouvant à une distance $r$ d'un point $I$ correspond au pourtour du carré, de centre $I$, de côtés parallèles aux axes et de longueurs $2r$.
Sur le graphique ci-dessus, le carré dessiné :

    1. À quelle valeur de $k$ correspond le carré noir ?

    2. Quelle serait l'origine de l'élément de squelette en considérant cette valeur de $k$ ?

  1. On choisit $k=9$. Quelle serait l'origine de l'élément de squelette en considérant cette valeur de $k$ ?

  2. On choisit $k=11$. Quelle serait l'origine de l'élément de squelette en considérant cette valeur de $k$ ?

  3. Peut-on savoir à coup sûr, en prenant une valeur de $k$ inférieure au égale à 11, si le combattant dont on a trouvé un élément de squelette était un combattant de la Triple-Entente (France + Royaume-Uni + Russie) ou de la Triple-Alliance (Allemagne + Autriche-Hongrie + Italie) ?

Code de déblocage de la correction :

L'algorithme des $k$ plus proches voisins, comme tout algorithme d'apprentissage supervisé est soumis aux biais d'apprentissage.
Un biais d'apprentissage signifie que l'on entraîne un algorithme d'apprentissage sur un ensemble de données qui conduit à favoriser de manière erronée une catégorie de manière systématique.

Voici deux exemples réels de cas où ce biais d'apprentissage a pu avoir un impact social important :

Implémentation de l'algorithme des $k$ plus proches voisins

Pour implémenter cet algorithme, il nous faut :

  1. Une table de données. Cette table peut être une liste ou un dictionnaire.

  2. Une distance entre deux données.

  3. Une cible.

La notion de distance est un élément central de cet algorithme. Voici quelques distances possibles :

La distance euclidienne (dans un repère orthonormé)

Soit deux données $donnee_{1}$ et $donnee_{2}$ de coordonnées données par les tuples respectifs $(x_{1}, y_{1})$ et $(x_{2}, y_{2})$.

$distance(donnee_{1},donnee_{2}) = \sqrt{(x_{1}-x_{2})^2+(y_{1}-y_{2})^2}$

La distance de Manhattan

Soit deux données $donnee_{1}(x_{1}, y_{1})$ et $donnee_{2}(x_{2}, y_{2})$.

$distance(donnee_{1},donnee_{2}) = \lvert{x_{1}-x_{2}}\rvert+\lvert{y_{1}-y_{2}}\rvert$.

La distance de Tchebychev

Soit deux données $donnee_{1}(x_{1}, y_{1})$ et $donnee_{2}(x_{2}, y_{2})$.

$distance(donnee_{1},donnee_{2}) = max(\lvert{x_{1}-x_{2}}\rvert,\lvert{y_{1}-y_{2}}\rvert$).

Voici le début la structure globale de l'algorithme des $k$ plus proches voisins, sachant que :

def k_plus_proches_voisins(table, cible, k):
    """Renvoie la liste des $k$ plus proches voisins de la cible"""
    
    
    def distance_cible(donnee):
        """ renvoie la distance entre la donnée et la cible"""
        
        return distance
	
	# On trie la table de manière croissante en utilisant la distance comme critère. 
    table_triee = sorted(table, key=distance_cible)
	
	# gestion de la liste des k plus proches voisins
    proches_voisins = []						# initialisation vide
    for i in range(k): 
        proches_voisins.append(table_triee[i]) 	# On ajoute les $k$ premières valeurs
        
    return proches_voisins # On renvoie la liste des $k$ plus proches voisins.
# On peut utiliser des listes ou des dictionnaires
table = [['t1', 1, 28], ['t1', 3, 27.2], ['t1', 8, 37.6], ['t1', 13, 40.7], ['t2', 2, 30], ['t2', 3, 26], ['t2', 10, 39], ['t2', 15, 35.5]]
# 't1' représente le type 1
# 't2' représente le type 2
# La première valeur numérique correspond à la valeur de la caractéristique 1
# La deuxième valeur numérique correspond à la valeur de la caractéristique 2

# Caractéristiques 1 et 2 de la cible
cible = [7, 28.4]

# Valeur de $k$ 
k = 3

def k_plus_proches_voisins(table, cible, k):
    """Renvoie la liste des $k$ plus proches voisins de la cible"""
    
    def distance_cible(donnee):
        """ renvoie la distance entre la donnée et la cible"""
        
        distance = abs(donnee[1]-cible[0]) + abs(donnee[2]-cible[1])
        
        return distance
    
    table_triee = sorted(table, key=distance_cible)
    
    proches_voisins = []
    
    for i in range(k): 
        proches_voisins.append(table_triee[i])
        
    return proches_voisins

k_plus_proches_voisins(table, cible, k)

    On considère le code ci-dessous.

    from math import *
    # from random import *
    import matplotlib.pyplot as plt
    # import numpy as np
    # from scipy.stats import linregress
    
    # Données de type 1
    liste_x_1 = [1, 3, 8, 13]
    liste_y_1 = [28, 27.2, 37.6, 40.7]
    
    # Données de type 2
    liste_x_2 = [2, 3, 10, 15]
    liste_y_2 = [30, 26, 39, 35.5]
    
    plt.axis([0, 15, 0, 50]) # Attention [x1, x2, y1, y2]
    plt.axis('equal')
    plt.xlabel('Caractéristique 1')
    plt.ylabel('Caractérstique 2')
    plt.title('Représentation des deux types')
    plt.grid()
    plt.scatter(liste_x_1, liste_y_1, label='type 1')
    plt.scatter(liste_x_2, liste_y_2, label='type 2')
    
    plt.scatter(7, 28.4, label='cible')
    plt.legend()
    plt.show()
    
    table = [['t1', 1, 28], ['t1', 3, 27.2], ['t1', 8, 37.6], ['t1', 13, 40.7], ['t2', 2, 30], ['t2', 3, 26], ['t2', 10, 39], ['t2', 15, 35.5]]
    cible = [7, 28.4]
    k = 3
    
    def k_plus_proches_voisins(table, cible, k):
        """Revoie la liste des k plus proches voisins de la cible"""
            
        def distance_cible(donnee):
            """ renvoie la distance entre la donnée et la cible, on choisit la distance de Manhattan"""
            
            distance = abs(donnee[1]-cible[0]) + abs(donnee[2]-cible[1])
            
            return distance
        
        table_triee = sorted(table, key=distance_cible)
        
        proches_voisins = []
        
        for i in range(k): 
            proches_voisins.append(table_triee[i])
            
        return proches_voisins
    
    print("La liste des ", k, " plus proches voisins de la cible : ", k_plus_proches_voisins(table, cible, k))
    

    Vous pouvez exécuter ce code directement sur ce trinket.

  1. Afficher le résultat de la fonction k_plus_proches_voisins(table, cible, k). Quel est le type de la cible ?

  2. Quelle est la valeur de $k$ ?

  3. Quelle distance a-t-on utilisée ?

  4. Utiliser d'autres valeurs de $k$. Quel est l'effet sur le type de la cible ?

  5. Changer la distance. Programmer la distance de Tchebychev. Quel est l'effet sur le type de la cible ?

Code de déblocage de la correction :

  1. Faire une recherche sur la distance de Hamming.

  2. Donner la distance de Hamming :

    1. entre $100100$ et $100010$ ;

    2. entre $210510$ et $201511$ ;

    3. entre "maille" et "paille".

  3. Écrire, en langage Python, une fonction hamming qui renvoie la distance de Hamming entre deux éléments.

Code de déblocage de la correction :

Exercices

Chevaliers et fantassins

Le but est d'étudier plus en détail l'exemple qui a servi d'introduction visuelle à l'algorithme des $k$ plus proches voisins.

  1. Voici une fonction impor :

    import csv
    def impor(nom):
        lecteur = csv.DictReader(open(nom + '.csv', "r", encoding='utf-8-sig'), delimiter=";")
        return [ligne for ligne in lecteur]
    

    La fonction DictReader du module csv permet d'ouvrir un fichier csv et de créer un itérable de dictionnaires. La première ligne du fichier csv donne l'ensemble des clés des dictionnaires et chaque autre ligne donnera les valeurs d'un dictionnaire.

    Si le fichier csv monty_python.csv est donné par le contenu suivant où chaque élément est séparé par le symbole ;

    nom;prenom
    Graham;Chapman
    John;Cleese
    Terry;Gilliam
    Eric;Idle
    Terry;Jones
    Michael;Palin

    alors l'instruction impor("monty_python") renvoie la liste suivante :

    [{'nom': 'Graham', 'prenom': 'Chapman'}, 
     {'nom': 'John', 'prenom': 'Cleese'},
     {'nom': 'Terry', 'prenom': 'Gilliam'}, 
     {'nom': 'Eric', 'prenom': 'Idle'}, 
     {'nom': 'Terry', 'prenom': 'Jones'}, 
     {'nom': 'Michael', 'prenom': 'Palin'}]

    Expliquer comment utiliser cette fonction afin de récupérer dans une variable nommée combattants la liste des personnages associés à leur force, courage et type ; données initialement dans un fichier personnages.csv accessible ici directement.

    Tester le bon fonctionnement de la fonction avec le fichier personnages.csv accessible ici directement.

    Le fichier personnages.csv téléchargé doit être placé au niveau du répertoire courant de travail de votre IDE.
    Si vous ne connaissez pas le répertoire courant de travail ou si vous voulez placer le fichier csv dans le même répertoire que le fichier .py contenant la fonction impor, il vous suffit tout ou partie du code suivant :

    import os            # import du module permettant d'utiliser les fonctionnalités dépendant du système d'exploitation
    print(os.getcwd())   # Pour afficher le répertoire courant de travail usuel
    os.chdir(os.path.dirname(os.path.abspath(__file__)))  # pour travailler désormais dans le répertoire du fichier python exécuté
    print(os.getcwd())   # pour vérifier le répertoire courant de travail modifié     
  2. Proposer une fonction est_personnage qui prend en paramètres une liste de personnages comme celle renvoyée par la fonction de la question précédente et un nom sous forme de chaîne de caractères. Cette fonction renvoie un booléen donnant l'appartenance ou non d'un personnage portant le nom donné comme argument dans cette liste.

    Utiliser cette fonction afin de savoir s'il existe un combattant du nom de "Lis" ?

  3. Trier la table des personnages par le type.

    1. La fonction sorted permet de renvoyer une liste triée suivant un critère qui est précisé comme fonction donnée en tant qu'argument de l'attribut key : liste_triee = sorted(liste_initiale, key=fonction_de_critere_prioritaire_de_tri).
      Vous trouverez un exemple d'utilisation dans le deuxième exemple de cette page officielle de la documentation du langage Python.

    2. Vous pouvez utiliser la lambda-fonction lambda x: x["Type"] comme montré dans le cours sur le tri d'une table ou dans la documentation proposée ci-dessus.

  4. Écrire et utiliser l'algorithme des $k$ plus proches voisins avec $k=7$ et la distance euclidienne pour savoir quel sera le type du personnage nommé "popsi", de force 12 et de courage 12.5 selon la table des personnages connus.

    1. Vous pouvez compléter et adapter la forme générale du script proposé dans la propriété 2 de ce chapitre.

    2. Pour définir la fonction distance_cible, vous pouvez utiliser la fonction eval. Cette fonction peut prendre une chaîne de caractères correspondant à une expression en Python comme argument et renvoie la valeur calculée pour cette expression (cf. documentation officielle).

Code de déblocage de la correction :

Il est possible de remplacer l'utilisation de la lambda-fonction de la question 3 par la création préalable au tri d'une fonction qui à chaque dictionnaire représentant un personnage associe son type comme ainsi :

# saisir avant le contenu du script du 1.
def ordre_type(dico: dict) - >str: # dico est un dictionnaire représentant un personnage
    return dico['Type']         # le type du personnage est renvoyé

combattants_tries = sorted(combattants, key=ordre_type)
print(combattants_tries)

Le but est d'obtenir des graphiques représentant sous forme de nuages de points les données de l'exercice précédent, graphiques similaires à ceux utilisés dans la première partie de ce chapitre.

En abscisse sera placé le niveau de force, en ordonnée celui du courage.

  1. Écrire un script qui stocke : dans une variable :

    • liste_chevalier_x la liste des niveaux de force pour les seuls chevaliers

    • liste_chevalier_y la liste des niveaux de courage pour les seuls chevaliers

    • liste_fantassin_x la liste des niveaux de force pour les seuls fantassins

    • liste_fantassin_y la liste des niveaux de courage pour les seuls fantassins

    Attention à avoir correctement classé la table afin que les éléments de même index pour chacune des listes correspondent à un même combattant.

  2. Créer un script qui affichage le nuage de points des personnages de la table en fonction de leur force (en abscisse) et de la courage (en ordonnée).

  3. Rajouter le personnage cible nommé "popsi", de force 5 et de courage 12.5 ainsi que le cercle centré sur ce personnage et de rayon 6.

  4. Quelle valeur de $k$ correspond à ce cercle ?
    Quel type est associé avec cette valeur et cette distance au personnage cible ?

    Code de déblocage de la correction :

  5. Modifier le script précédent afin de ne prendre en compte que le niveau de courage : il affiche au lieu du cercle un rectangle de largeur 5, centré en hauteur sur le point cible.

    Quel type est associé avec cette valeur et cette distance au personnage cible ?

  6. Modifier le script précédent afin de ne prendre en compte que le niveau de force : il affiche au lieu du cercle un rectangle de largeur 5, centré en largeur sur le point cible.

    Quel type est associé avec cette valeur et cette distance au personnage cible ?

Code de déblocage de la correction :

Harry potter

Source : NSI 1re générale (Numérique et sciences informatiques) - Prépabac, nouveau programme de Première (2020-2021) – Céline Adobet, Guillaume Connan, Gérard Rozsavolgyi, Laurent Signac Lien vers le manuel de chez Hatier Objectif bac page 266

À l’entrée à l’école de Poudlard, le Choixpeau magique répartit les élèves dans les différentes maisons (Gryffondor, Serpentard, Serdaigle et Poufsouffle) en fonction de leur courage, leur loyauté, leur sagesse et leur malice.

Le Choixpeau magique dispose d’un fichier CSV dans lequel sont répertoriées les données d’un échantillon d’élèves. Le fichier ChoixpeauMagique.csv est téléchargeable à cet endroit : choixpeauMagique.csv

Nom Courage Loyauté Sagesse Malice Maison
Adrian 9 4 7 10 Serpentard
Andrew 9 3 4 7 Gryffondor
Angelina 10 6 5 9 Gryffondor
Anthony 2 8 8 3 Serdaigle

On souhaite que Choixpeau magique oriente :

Nom Courage Loyauté Sagesse Malice
Hermione 8 6 6 6
Drago 6 6 5 8
Cho 7 6 9 6
Cédric 7 10 5 6

    On décompose l'exercice en 5 parties :

  1. Modéliser un élève

    On modélise un élève par un dictionnaire.

    Exemple : {'Nom': 'Bellatrix', 'Courage': 10, 'Loyauté': 4, 'Sagesse': 9, 'Malice': 9, 'Maison': 'Serpentard'}.

    1. Donner la modélisation de l'élève Anthony.

    2. On utilise la distance de Manhattan.

      1. Vérifier à la main que la distance entre Hermione et Adrian est égale à 8.

      2. Quelle est la distance entre Angelina et Drago ?

      3. Écrire le code d'une fonction distance qui prend deux élèves en paramètre et qui renvoie la distance entre ces deux élèves. Ne pas oublier de préciser la documentation et donner au moins un test.

    Code de déblocage de la correction :

  2. Charger les données de la table

    Se reporter au chapitre sur les tables afin d'écrire une fonction qui permet de récupérer les données des élèves d'un fichier CSV pour les stocker dans une liste. On doit obtenir une liste de dictionnaires.

    Code de déblocage de la correction :

  3. Trouver la maison majoritaire
    1. Écrire une fonction frequence_des_maisons(table) qui prend en paramètre une table d'élèves et qui renvoie le dictionnaire des fréquences des maisons. Vous devez obtenir : {'Serpentar': 12, 'Gryffondor': 17, 'Serdaigle': 11, 'Poufsouffle': 10}.

    2. Écrire une fonction maison_majoritaire(table) qui prend en paramètre une table d'élèves et qui renvoie le nom de la maison la plus représentée.

    Code de déblocage de la correction :

  4. Algorithme des 7 plus proches voisins

    On dispose d'une table et d'une nouvelle élève Niue qui n'a pas encore de maison. On sait que cette élève est de "Courage" de niveau 7, de "Loyauté" de niveau 8, 5 en niveau de "Sagesse" et 4 en niveau de "Malice".
    On cherche les 7 plus proches voisins de ce nouveau.

    1. Écrire l'algorithme des 7 plus proches voisins.

    2. Implémenter cet algorithme en python.

    3. Faire un test avec 'Hermione'. Vous devez obtenir les 7 voisins suivants : [{'nom': 'Cormac', 'Courage': 9, 'Loyauté': 6, 'sagesse': 5, 'malice': 4, 'maison': 'Gryffondor'}, {'nom': 'Milicent', 'Courage': 9, 'Loyauté': 3, 'sagesse': 5, 'malice': 6, 'maison': 'Serpentar'}, {'nom': 'Neville', 'Courage': 10, 'Loyauté': 5, 'Sagesse': 6, 'Malice': 4, 'Maison': 'Gryffondor'}, {'nom': 'Padma', 'Courage': 6, 'Loyauté': 6, 'Sagesse': 6, 'Malice': 9, 'Maison': 'Serdaigle'}, {'nom': 'Susan', 'Courage': 5, 'loyauté': 6, 'Sagesse': 5, 'malice': 5, 'Maison': 'Poufsouffle'}, {'nom': 'Angelina', 'Courage': 10, 'loyauté': 6, 'Sagesse': 5, 'Malice': 9, 'Maison': 'Gryffondor'}, {'nom': 'Colin', 'Courage': 10, 'Loyauté': 7, 'Sagesse': 4, 'Malice': 7, 'Maison': 'Gryffondor'}]

      La maison attribuée pour 'Hermione' est 'Gryffondor'.

    Code de déblocage de la correction :

  5. Attribuer une maison

    On dispose d'une table et de cette nouvelle élève Niue qui n'a pas encore de maison. On sait que cette élève est de "Courage" de niveau 7, de "Loyauté" de niveau 8, 5 en niveau de "Sagesse" et 4 en niveau de "Malice".
    On cherche désormais à lui attribuer une maison.

    Implémenter en python l'algorithme de l'attribution :

    1. Trouver dans la table les 7 plus proches voisins de cette nouvelle élève.

    2. Parmi ces proches voisins, trouver la maison majoritaire.

    3. Renvoyer la maison majoritaire pour cette élève "Niue".

    Faire un test avec 'Hermione'. Vous devez obtenir comme maison "Gryffondor".

Code de déblocage de la correction :

Pokemon : exercice facultatif

Source : NSI 1re générale (Numérique et sciences informatiques) - Prépabac, nouveau programme de Première (2020-2021) – Céline Adobet, Guillaume Connan, Gérard Rozsavolgyi, Laurent Signac Lien vers le manuel de chez Hatier Exercice page 246

Vous avez ci-dessous à disposition un fichier csv dans lequel vous avez environ 400 Pokemon répartis selon 18 types.

fichier csv à télécharger

Je vous donne un nouveau Pokemon : Hippodocus qui possède les caractéristiques suivantes :

Questions :

  1. Quel type pouvez-vous attribuer à ce Pokemon ?

  2. Varier les valeurs de $k$ et les différents types de distances. Le résultat reste-il stable ?

  3. Code de déblocage de la correction :

  4. Observer la table "pokemon", surtout les effectifs des différents types.
    Pensez-vous que la table soit efficace pour entrainer une intelligence artificielle à la reconnaissance des types pokemon ?

  5. Code de déblocage de la correction :

Complexité/coût de l'algorithme KNN

La complexité est abordée dans le chapitre A2 : complexité d'un algorithme.

La complexité de l'algorithme KNN repose sur la complexité du tri de la table.
D'après la documentation du langage Python, le tri de la table dans sortedselon la key distance est en $ O(n\log(n))$. Cela veut dire que son coût est comparable à $n \log(n)$ ($n$ est la taille de la table à trier). Dans ce cas on parle de complexité quasi-linéaire.

Première approche du coût d'un algorithme :

Le coût d'un algorithme dépend du nombre d'opérations élémentaires (arithmétiques ou logiques) ainsi que d'affectations nécessaires à son exécution.

Le coût dépend de la donnée elle-même. Dans notre cas, la donnée est une table et la complexité est celle du tri croissant de la table. Si la table est déjà triée, il n'y aura aucun tri à effectuer, on a une situation très favorable. Inversement, on peut facilement imaginer une situation très défavorable (table triée dans l'ordre décroissant).

On parle de plusieurs types de complexité :

Dans l'algorithme naïf, on admet que le temps mis pour déterminer les 5 plus proches voisins d’une cible dans un échantillon de taille 10 est de 1 ms. Vérifier que le temps mis pour déterminer les 5 plus proches voisins d'une cible dans un échantillon de taille 50 est de 8,5 ms de taille 50 000 de 23 494 ms.

  • penser à calculer les valeurs de $n \log(n)$ pour $n=10$ ; $n=50$ et $n=50 000$;

  • penser à faire un tableau de valeurs.

Code de déblocage de la correction :

Pour les curieux : vers l'intelligence artificielle et le machine learning

Le machine learning est un concept utilisé en intelligence artificielle. Il s'agit d'entraîner une machine à apprendre à reconnaitre certaines formes. On utilise une base d'entraînement pour la machine. L'algorithme knn donne une méthode qui permet d'utiliser cette base d'entrainement.

On vous propose une approche de reconnaissance des chiffres :

Aperçu du fichier principal :

Il y a plusieurs fichiers à télécharger, outre le fichier principal, pour utiliser ce fichier:

Merci à Goery Valance pour avoir accepté de partager dans cette partie ses documents.

QCM

Questions issues de la Banque Nationale de Sujets

Propriétaire des ressources ci-dessous : ministère de l'Éducation nationale et de la jeunesse, licence CC BY SA NC

Voici une sélection de questions issues de la banque nationale de sujets, répondez à ces questions (attention, cette sélection n'est pas exhaustive).

On a représenté sur un quadrillage les éléments de quatre classes (chaque classe est représentée par un carré, un triangle, un losange ou un disque) ainsi qu’un nouvel élément X.

En appliquant l'algorithme des $k$ plus proches voisins pour la distance usuelle dans le plan, avec $k=5$, à quelle classe est affecté le nouvel élément X ?

Réponses :

A- La classe des carrés.

B- La classe des triangles.

C- La classe des losanges.

D- La classe des disques.

Une seule des affirmations suivantes est vraie :

Réponses :

A- L'algorithme des $k$ plus proches voisins a pour but de déterminer les $k$ plus proches voisins d'une observation dans un ensemble de données.

B- L'algorithme des $k$ plus proches voisins a pour but de déterminer la classe d'une observation à partir des classes de ses $k$ plus proches voisins.

C- L'algorithme des $k$ plus proches voisins a pour but de déterminer dans un ensemble de données le sous-ensemble à $k$ éléments qui sont les plus proches les uns des autres.

D- L'algorithme des $k$ plus proches voisins a pour but de déterminer les éléments d'un ensemble de données appartenant à une même classe.

On dispose d’une table de données de villes européennes. On utilise ensuite l’algorithme des $k$ plus proches voisins pour compléter automatiquement cette base avec de nouvelles villes.
Ci-dessous, on a extrait les 7 villes connues de la base de données les plus proches de Davos.

En appliquant l’algorithme des 4 plus proches voisins, quel sera le pays prédit pour la ville de Davos ?

Réponses :

A- Allemagne.

B- Autriche.

C- Italie.

D- Suisse.

À quelle catégorie appartient l’algorithme des $k$ plus proches voisins ?

Réponses :

A- Algorithmes de tri.

B- Algorithmes gloutons.

C- Algorithmes de recherche de chemins.

D- Algorithmes de classification et d’apprentissage.

Autres QCM

Dans le quadrillage ci-dessous 14 points sont dessinés, dont 7 de la classe C1, avec des ronds noirs •, et 7 de la classe C2, avec des losanges ◇.
On introduit un nouveau point A, dont on cherche la classe à l'aide d'un algorithme des $k$ plus proches voisins pour la distance géométrique habituelle, en faisant varier la valeur de $k$ parmi 1, 3 et 5.
Quelle est la bonne réponse (sous la forme d'un triplet de classes pour le triplet (1, 3, 5) des valeurs de $k$) ?

Réponses :

A- C1, C2, C3.

B- C2, C1, C2.

C- C2, C2, C2.

D- C2, C1, C1.

Soient les points de coordonnées suivantes :
A(4, 2) B(1, 5) C(3, 2) D(2, 0) E(7, 6) F(6, 3) G(6, 2) H(8, 5)

En utilisant la distance euclidienne, quels sont les deux plus proches voisins du point I(4, 5) ?

Réponses :

A- Les points A et B.

B- Les points C et D.

C- Les points E et F.

D- Les points G et H.

Générateur aléatoire de questions sur ce chapitre

Il faut actualiser la page pour changer de question. Propriétaire de la ressource : le site GeNumsi en licence CC BY_NC-SA

Sitographie/Bibliographie

NSI 1re générale (Numérique et sciences informatiques) - Prépabac, nouveau programme de Première (2020-2021) – Céline Adobet, Guillaume Connan, Gérard Rozsavolgyi, Laurent Signac Lien vers le manuel de chez Hatier.

Savoir et savoir-faire

Licence Creative Commons
Les différents auteurs mettent l'ensemble du site à disposition selon les termes de la licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International